---
sidebar_position: 10
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Paranoid Models

Sequelize supports the concept of _paranoid_ tables.
A _paranoid_ table is one that, when told to delete a record,
will not truly delete it.
Instead, it will record that the model is deleted by setting its "deleted at" column to the current timestamp.

This means that paranoid tables perform a _soft-deletion_ of records, instead of a _hard-deletion_.

## Defining a model as paranoid

To make a model paranoid, you must use the `@DeletedAt` decorator on an attribute.
That attribute will then be used by Sequelize to record the deletion timestamp.

<Tabs groupId="ts-js">
<TabItem value="ts" label="TypeScript">

```typescript
import { InferCreationAttributes, InferAttributes, Model } from '@sequelize/core';
import { DeletedAt } from '@sequelize/core/decorators-legacy';

class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
  // highlight-next-line
  @DeletedAt
  declare deletedAt: Date | null;
}
```

</TabItem>
<TabItem value="js" label="JavaScript">

```javascript
import { Model } from '@sequelize/core';
import { DeletedAt } from '@sequelize/core/decorators-legacy';

class User extends Model {
  // highlight-next-line
  @DeletedAt
  deletedAt;
}
```

</TabItem>
</Tabs>

## Deleting

When you call the `destroy` method, a soft-deletion will happen:

```js
await Post.destroy({
  where: {
    id: 1,
  },
});
// UPDATE "posts" SET "deletedAt"=[timestamp] WHERE "deletedAt" IS NULL AND "id" = 1
```

If you really want a hard-deletion and your model is paranoid, you can force it using the `force: true` option:

```js
await Post.destroy({
  where: {
    id: 1,
  },
  force: true,
});
// DELETE FROM "posts" WHERE "id" = 1
```

The above examples used the static `destroy` method as an example (`Post.destroy`), but everything works in the same way with the instance method:

```js
const post = await Post.create({ title: 'test' });
console.log(post instanceof Post); // true
await post.destroy(); // Would just set the `deletedAt` flag
await post.destroy({ force: true }); // Would really delete the record
```

## Restoring

To restore soft-deleted records, you can use the `restore` method, which comes both in the static version as well as in the instance version:

```js
// Example showing the instance `restore` method
// We create a post, soft-delete it and then restore it back
const post = await Post.create({ title: 'test' });
console.log(post instanceof Post); // true
await post.destroy();
console.log('soft-deleted!');
await post.restore();
console.log('restored!');

// Example showing the static `restore` method.
// Restoring every soft-deleted post with more than 100 likes
await Post.restore({
  where: {
    likes: {
      [Op.gt]: 100,
    },
  },
});
```

## Behavior with other queries

Every query performed by Sequelize will automatically ignore soft-deleted records (except raw queries, of course).

This means that, for example, the `findAll` method will not see the soft-deleted records, fetching only the ones that were not deleted.

Even if you simply call `findByPk` providing the primary key of a soft-deleted record, the result will be `null` as if that record didn't exist.

If you really want to let the query see the soft-deleted records, you can pass the `paranoid: false` option to the query method. For example:

```js
await Post.findByPk(123); // This will return `null` if the record of id 123 is soft-deleted
await Post.findByPk(123, { paranoid: false }); // This will retrieve the record

await Post.findAll({
  where: { foo: 'bar' },
}); // This will not retrieve soft-deleted records

await Post.findAll({
  where: { foo: 'bar' },
  paranoid: false,
}); // This will also retrieve soft-deleted records
```

### Eager-loading soft-deleted records

:::note

Eager-loading is described in depth in the [SELECT Queries: In Depth guide](../querying/select-in-depth.md#eager-loading-include).

:::

If you want to eager load soft deleted records, you can do that by setting `include.paranoid` to `false`:

```js
User.findAll({
  include: [
    {
      association: 'projects',
      paranoid: false,
    },
  ],
});
```
